<?php

/**
 * CCoreLabsSmtpServer
 *
 * @author Usenko Timur <usenko.timur@gmail.com>
 * @package labs
 */

/**
 * @package labs
 */
class CCoreLabsSmtpServer
{
	#<editor-fold defaultstate="collapsed" desc="constants">
	const CRLF = "\r\n";

	const DATA_NEXT_FILE = '.system.next.data';
	const DATA_UIDL_FILE = '.system.last.uid.data';
	
	#</editor-fold>
	#<editor-fold defaultstate="collapsed" desc="private">
	/**
	 * @var string
	 */
	private $_sFilePathToSmtpStorage;
	#</editor-fold>

	/**
	 * @param string $sFilePathToSmtpStorage
	 * @return CCoreLabsSmtpServer
	 */
	public function __construct($sFilePathToSmtpStorage)
	{
		$this->_sFilePathToSmtpStorage = trim($sFilePathToSmtpStorage);
	}

	/**
	 * @param string $sCommandLine
	 * @return string
	 */
	public function Response($sCommandLine)
	{
		$aResponse = array();
		$sPrevCmd = $this->_getNextResponseCommand();
		if (strlen($sPrevCmd) > 0)
		{
			switch ($sPrevCmd)
			{
				case 'AUTH LOGIN':
					$this->_setNextResponseCommand('AUTH PASSWORD');
					$aResponse[] = '334 UGFzc3dvcmQ6';
					break;
				case 'AUTH PASSWORD':
					$this->_setNextResponseCommand('');
					$aResponse[] = '235 authenticated';
					break;
				case 'DATA':
					@file_put_contents($this->_sFilePathToSmtpStorage.DIRECTORY_SEPARATOR.
						$this->_getNextUidFileName(), $sCommandLine);
				
					$this->_setNextResponseCommand('');
					$aResponse[] = '250 message accepted for delivery';
					break;
			}
		}
		else
		{
			$aCommandArray = explode(' ', trim($sCommandLine), 2);
			$sCommand = trim($aCommandArray[0]);

			$sFirstArgument = isset($aCommandArray[1]) ? trim($aCommandArray[1]) : null;
			
			switch ($sCommand)
			{
				case 'DATA':
					$this->_setNextResponseCommand('DATA');
					$aResponse[] = $this->_getSuccesResponseTextFromCommand($sCommand);
					break;
				case '':
				case 'MAIL':
				case 'RCPT':
				case 'QUIT':
					$this->_setNextResponseCommand('');
					$aResponse[] = $this->_getSuccesResponseTextFromCommand($sCommand);
					break;
				case 'EHLO':
				case 'HELO':
					$this->_setNextResponseCommand('');
					$aResponse[] = '250-u-server.dom2.local domain name should be qualified localhost';
					$aResponse[] = '250-HELP';
					$aResponse[] = '250-PIPELINING';
					$aResponse[] = '250-ETRN';
					$aResponse[] = '250-DSN';
					$aResponse[] = '250-TURN';
					$aResponse[] = '250-ATRN';
					$aResponse[] = '250-SIZE';
					$aResponse[] = '250-STARTTLS';
					$aResponse[] = '250-AUTH=LOGIN';
					$aResponse[] = '250-AUTH LOGIN PLAIN CRAM-MD5 DIGEST-MD5 MSN';
					$aResponse[] = '250 '.$sCommand;
					break;
				case 'AUTH':
					if ('AUTH LOGIN' === trim($sCommandLine))
					{
						$this->_setNextResponseCommand('AUTH LOGIN');
						$aResponse[] = '334 VXNlcm5hbWU6';
					}
					break;
				default:
					$aResponse[] = '500 [unknown command: '.$sCommand.']';
					break;
			}
		}

		if (0 === count($aResponse))
		{
			$aResponse[] = '500 [error]';
		}
		
		return implode(self::CRLF, $aResponse).self::CRLF;
	}

	/**
	 * @param string $sCommand
	 * @return string
	 */
	private function _getSuccesResponseTextFromCommand($sCommand)
	{
		switch ($sCommand)
		{
			case '':
				return '220 smtp server is glad to see you!';
			case 'MAIL':
				return '250 sender accepted';
			case 'RCPT':
				return '250 RCPT accepted';
			case 'DATA':
				return '354 Enter mail, end with "." on a line by itself';
			case 'QUIT':
				return '221 smtp server closing connection';
		}
		
		return '';
	}

	/**
	 * @return string
	 */
	private function _getNextUidFileName()
	{
		$iNum = 0;
		if (file_exists($this->_sFilePathToSmtpStorage.DIRECTORY_SEPARATOR.self::DATA_UIDL_FILE))
		{
			$iNum = (int) @file_get_contents($this->_sFilePathToSmtpStorage.DIRECTORY_SEPARATOR.self::DATA_UIDL_FILE);
		}
		
		$iNum++;
		@file_put_contents($this->_sFilePathToSmtpStorage.DIRECTORY_SEPARATOR.self::DATA_UIDL_FILE, $iNum);
		return 'uid_'.str_pad($iNum, 3, '0', STR_PAD_LEFT).'.eml';
	}

	/**
	 * @return string
	 */
	private function _getNextResponseCommand()
	{
		if (file_exists($this->_sFilePathToSmtpStorage.DIRECTORY_SEPARATOR.self::DATA_NEXT_FILE))
		{
			return @file_get_contents($this->_sFilePathToSmtpStorage.DIRECTORY_SEPARATOR.self::DATA_NEXT_FILE);
		}

		return '';
	}

	/**
	 * @param string $sCommand
	 * @return bool
	 */
	private function _setNextResponseCommand($sCommand)
	{
		return (false !==@file_put_contents($this->_sFilePathToSmtpStorage.DIRECTORY_SEPARATOR.self::DATA_NEXT_FILE, $sCommand));
	}
}